﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KP_CommonLibrary.KP_CommonControls.NumericInput
{
   public abstract class MaskManagerStated : MaskManager
{
    // Fields
    private MaskManagerState backupState;
    private StateChangeType backupType = StateChangeType.Terminator;
    private int cachedDCP = -1;
    private int cachedDSA = -1;
    private MaskManagerState cachedDState;
    private string cachedDT;
    private MaskManagerState currentState;

    // Methods
    protected MaskManagerStated(MaskManagerState initialState)
    {
        this.SetInitialState(initialState);
    }

    protected bool Apply(MaskManagerState newState, StateChangeType changeType)
    {
        return this.Apply(newState, changeType, false);
    }

    protected bool Apply(MaskManagerState newState, StateChangeType changeType, bool isNeededKeyCheck)
    {
        if (!this.IsValid(newState))
        {
            return false;
        }
        if (newState.IsSame(this.CurrentState))
        {
            return false;
        }
        string editText = this.GetEditText(newState);
        if (!isNeededKeyCheck)
        {
            if (this.GetCurrentEditText() != editText)
            {
                if (!this.RaiseEditTextChanging(editText))
                {
                    return false;
                }
                this.ApplyInternal(newState, changeType);
                base.RaiseEditTextChanged();
            }
            else
            {
                this.ApplyInternal(newState, changeType);
            }
        }
        return true;
    }

    private void ApplyInternal(MaskManagerState newState, StateChangeType changeType)
    {
        if (this.backupType != changeType)
        {
            if (changeType != StateChangeType.Terminator)
            {
                this.backupState = this.currentState;
            }
            this.backupType = changeType;
        }
        this.currentState = newState;
    }

    public sealed override string GetCurrentEditText()
    {
        return this.GetEditText(this.CurrentState);
    }

    public sealed override object GetCurrentEditValue()
    {
        return this.GetEditValue(this.CurrentState);
    }

    protected abstract int GetCursorPosition(MaskManagerState state);
    protected abstract string GetDisplayText(MaskManagerState state);
    protected abstract string GetEditText(MaskManagerState state);
    protected abstract object GetEditValue(MaskManagerState state);
    protected abstract int GetSelectionAnchor(MaskManagerState state);
    protected virtual bool IsValid(MaskManagerState newState)
    {
        return true;
    }

    protected void SetInitialState(MaskManagerState newState)
    {
        this.backupState = null;
        this.currentState = newState;
        this.backupType = StateChangeType.Terminator;
    }

    public override bool SpinDown()
    {
        return base.CursorRight(false);
    }

    public override bool SpinUp()
    {
        return base.CursorLeft(false);
    }

    public override bool Undo()
    {
        if (!this.CanUndo)
        {
            return false;
        }
        if (!this.RaiseEditTextChanging(this.GetEditText(this.backupState)))
        {
            return false;
        }
        this.backupType = StateChangeType.Terminator;
        MaskManagerState currentState = this.currentState;
        this.currentState = this.backupState;
        this.backupState = currentState;
        base.RaiseEditTextChanged();
        return true;
    }

    private void VerifyCache()
    {
        if (!object.ReferenceEquals(this.cachedDState, this.CurrentState))
        {
            this.cachedDState = this.CurrentState;
            this.cachedDCP = -1;
            this.cachedDSA = -1;
            this.cachedDT = null;
        }
    }

    // Properties
    public override bool CanUndo
    {
        get
        {
            return ((this.backupState != null) && (this.currentState != null));
        }
    }

    protected MaskManagerState CurrentState
    {
        get
        {
            return this.currentState;
        }
    }

    public sealed override int DisplayCursorPosition
    {
        get
        {
            this.VerifyCache();
            if (this.cachedDCP < 0)
            {
                this.cachedDCP = this.GetCursorPosition(this.CurrentState);
            }
            return this.cachedDCP;
        }
    }

    public sealed override int DisplaySelectionAnchor
    {
        get
        {
            this.VerifyCache();
            if (this.cachedDSA < 0)
            {
                this.cachedDSA = this.GetSelectionAnchor(this.CurrentState);
            }
            return this.cachedDSA;
        }
    }

    public sealed override string DisplayText
    {
        get
        {
            this.VerifyCache();
            if (this.cachedDT == null)
            {
                this.cachedDT = this.GetDisplayText(this.CurrentState);
            }
            return this.cachedDT;
        }
    }

    // Nested Types
    protected enum StateChangeType
    {
        Insert,
        Delete,
        Terminator
    }
}     
}
